本文會提到
範疇(Scope)是指編譯器或 JavaScript 引擎藉由識別字名稱(identifier name)查找變數的一組規則。
編譯器會在程式執行前將程式碼由上到下逐行轉為電腦可懂的命令,稍後會執行這個編譯後的結果。注意,JavaScript 引擎會在每次執行前即時編譯程式碼(約幾毫秒 (ms) 而已),接著立刻執行編譯後的指令。
編譯有三步驟
var a = 2;
就會解析 var
、a
、=
、2
、;
。var
、a
、=
、2
、;
)組成抽象語法樹(abstract syntax tree,AST)在編譯的過程中,JavaScript 引擎、編譯器和範疇會互相溝通以完成工作。它們各自負責的任務有
範例如下,這裡有一段程式碼,在編譯這段程式碼時,JavaScript 引擎、編譯器和範疇三者會做什麼呢?
var a = 2;
其中,引擎對範疇的查找變數的動作,可分為兩種類型
a = 2
的 a 在等號的左邊,就是執行 LHS 查找動作。console.log(a)
,就是執行 RHS 查找動作。備註:函式宣告(例如:function foo() {...}
)並不是 LHS!這是因為在做函式宣告時,就同時做了宣告和值的定義,而非在執行階段設定其值。
若在目前執行的範疇找不到這個變數的時候,就會往外層的範疇搜尋,持續搜尋直到找到為止,或直到最外層的全域範疇(global scope);而這樣一層又一層的範疇就稱為「巢狀範疇」(nested scope)。
如下,console.log(a + b)
中,b 的 RHS 無法在 foo 中解析完成,但可到全域範疇解析出來。
const foo = (a) => {
console.log(a + b);
}
const b = 2;
foo(2); // 4
為什麼需要理解 LHS 和 RHS 呢?這是因為要看懂 JavaScript 報錯的原因。
當解析 identifier 失敗時
還有一種狀況,不論在 LHS 和 RHS 下,操作不合法的行為時,就會丟出 TypeError 的訊息。
const a = 2; a = 4;
的 a = 4
會導致 TypeError。const b = 2; b();
的 b()
會導致 TypeError。這裡有一個小範例,判斷哪裡發生了 LHS?哪裡發生了 RHS?
const foo = (a) => {
const b = a;
return a + b;
}
const c = foo(2);
答案是...
...
...
...
const c = ...
const b = ...
a = 2
const b = a
其中的 ... = a
對 a 取值return a + b
其中要對 a 取值return a + b
其中要對 b 取值foo(a)
其中要對 foo 取得其函數看完這篇文章,我們到底有什麼收穫呢?藉由本文可以理解到...
同步發表於部落格。
在編譯的時候,編譯器會先到範疇詢問變數 a 是否存在,若不存在就宣告這個 a 變數。
您好,想請問一下,編譯階段的這個動作也算是 LHS 嗎?
還是說只有在執行階段才算呢?
謝謝。